#pragma semicolon 1
#pragma newdecls required

#include <sourcemod>
#include <sdktools>
#include <sdkhooks>
#include <left4dhooks>

#define PLUGIN_VERSION "1.0"


public Plugin myinfo =
{
	name = "l4d2_jockey_knockback_with_effects",
	author = "豆瓣酱な",
	description = "jockey控住玩家击飞周围的玩家.",
	version = PLUGIN_VERSION,
	url = "https://gitee.com/sweet-and-sour-bombs/adfvsdsd"
};


// ConVars
ConVar g_cvKnockbackRadius;
ConVar g_cvHorizontalForce;
ConVar g_cvVerticalForce;
ConVar g_cvDamageAmount;

float g_fKnockbackRadius;
float g_fHorizontalForce;
float g_fVerticalForce;
float g_fDamageAmount;

// Sprites
int g_iBeamSprite;
int g_iHaloSprite;

// Sound
#define EXPLOSION_SOUND "ambient/explosions/explode_1.wav"

public void OnPluginStart()
{
	g_cvKnockbackRadius = CreateConVar("sm_jockeyknockback_radius", "200.0", "击飞范围和光圈大小", FCVAR_NOTIFY, true, 0.0);
	g_cvHorizontalForce = CreateConVar("sm_jockeyknockback_horizontal", "100.0", "水平击飞力度", FCVAR_NOTIFY, true, 0.0);
	g_cvVerticalForce = CreateConVar("sm_jockeyknockback_vertical", "251.0", "垂直击飞力度", FCVAR_NOTIFY, true, 0.0);
	g_cvDamageAmount = CreateConVar("sm_jockeyknockback_damage", "15.0", "击飞伤害值", FCVAR_NOTIFY, true, 0.0);

	HookConVarChange(g_cvKnockbackRadius, OnConVarChanged);
	HookConVarChange(g_cvHorizontalForce, OnConVarChanged);
	HookConVarChange(g_cvVerticalForce, OnConVarChanged);
	HookConVarChange(g_cvDamageAmount, OnConVarChanged);

	UpdateConVarValues();

	HookEvent("jockey_ride", Event_JockeyRide);
	
	// 自动生成配置文件
	//AutoExecConfig(true, "l4d2_jockey_knockback_with_effects");	
	
}

public void OnMapStart()
{
	// 预缓存材质
	g_iBeamSprite = PrecacheModel("materials/sprites/laserbeam.vmt");
	g_iHaloSprite = PrecacheModel("materials/sprites/halo01.vmt");
    
	// 预缓存音效
	PrecacheSound(EXPLOSION_SOUND);
}

public void OnConVarChanged(ConVar convar, const char[] oldValue, const char[] newValue)
{
	UpdateConVarValues();
}

void UpdateConVarValues()
{
	g_fKnockbackRadius = g_cvKnockbackRadius.FloatValue;
	g_fHorizontalForce = g_cvHorizontalForce.FloatValue;
	g_fVerticalForce = g_cvVerticalForce.FloatValue;
	g_fDamageAmount = g_cvDamageAmount.FloatValue;
}

public void Event_JockeyRide(Event event, const char[] name, bool dontBroadcast)
{
	int jockey = GetClientOfUserId(event.GetInt("userid"));
	int victim = GetClientOfUserId(event.GetInt("victim"));
    
	if (IsValidClient(jockey) && IsValidClient(victim))
	{
		CreateRingEffect(victim);
		PhysicsKnockbackNearbyPlayers(victim, jockey);
	}
}

void CreateRingEffect(int client)
{
	float pos[3];
	GetClientAbsOrigin(client, pos);
	pos[2] += 10.0;

	TE_SetupBeamRingPoint(pos, 10.0, g_fKnockbackRadius, g_iBeamSprite, g_iHaloSprite, 0,15, 1.0, 10.0, 0.0, {255, 100, 0, 255}, 20, 0);
	TE_SendToAll();
}

void PhysicsKnockbackNearbyPlayers(int victim, int attacker)
{
	if (!IsValidClient(victim) || !IsPlayerAlive(victim))
	return;

	float victimPos[3];
	GetClientAbsOrigin(victim, victimPos);

	for (int i = 1; i <= MaxClients; i++)
	{
		if (IsValidClient(i) && IsPlayerAlive(i) && GetClientTeam(i) == 2 && i != victim)
		{
			float targetPos[3];
			GetClientAbsOrigin(i, targetPos);
            
			if (GetVectorDistance(victimPos, targetPos) <= g_fKnockbackRadius)
			{
				float angles[3], velocity[3];
				GetClientEyeAngles(i, angles);
                
				velocity[0] = -Cosine(DegToRad(angles[1])) * g_fHorizontalForce;
				velocity[1] = -Sine(DegToRad(angles[1])) * g_fHorizontalForce;
				velocity[2] = g_fVerticalForce;
                
				// 击飞玩家
				TeleportEntity(i, NULL_VECTOR, NULL_VECTOR, velocity);
                
				// 造成伤害
				SDKHooks_TakeDamage(i, attacker, attacker, g_fDamageAmount, DMG_GENERIC);
                
				// 播放爆炸音效（在玩家位置）
				EmitSoundToAll(EXPLOSION_SOUND, i, SNDCHAN_AUTO, SNDLEVEL_NORMAL, SND_NOFLAGS, 1.0);
			}
		}
	}
}

bool IsValidClient(int client)
{
	return client > 0 && client <= MaxClients && IsClientInGame(client);
}